package org.fuys.coder.domain.recommend.service.impl;

import org.fuys.coder.common.entity.Pair;
import org.fuys.coder.domain.config.service.impl.CoderRecommendConfig;

import org.fuys.coder.common.constants.RedisConstants;
import org.fuys.coder.common.constants.ResultMessageConstants;
import org.fuys.coder.common.exception.BusinessException;
import org.fuys.coder.common.holder.CategoryVOHolder;
import org.fuys.coder.infrastructure.util.RedisUtil;
import org.fuys.coder.domain.category.model.vo.CategoryVO;
import org.fuys.coder.domain.category.service.ICategoryService;
import org.fuys.coder.domain.model.service.IUserModelService;
import org.fuys.coder.domain.recommend.service.IRecommendService;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.recommend.service.impl
 * @className: RecommendService
 * @author: WangJing
 * @description: 推荐服务
 * @date: 2024/6/25 16:20
 * @version: 1.0
 */
@Service
public class RecommendServiceImpl implements IRecommendService {

    @Resource
    private IUserModelService userModelService;

    @Resource
    private CoderRecommendConfig config;


    final private Random random=new Random();

    @Override
    public List<Integer> randomRecommend() {
//        final String redisKey = RedisConstants.REDIS_FIELD_CATEGORY + RedisConstants.REDIS_DESC_ALL;
        //采用的是json的方式存入拿取 因此这个警告真的只是警告
        //由于此部分是全部随机 所以不需要额外的处理 而只是使用commonGet获取全部的分类类型
        List<Integer> idList= CategoryVOHolder.getAll().stream().map(item->{
            return ((CategoryVO)item).getId();
        }).collect(Collectors.toList());
        //这里的改动是不会影响原本数据的 因为只会从redis中拿取副本
        if(idList.size()>config.getCategoryTypeNums()) {
            Collections.shuffle(idList);
            return idList.subList(0, config.getCategoryTypeNums());
        }
        return idList;
    }

    @Override
    public List<Integer> roughRecommend(Integer userId) {
        List<Pair<Integer, Double>> collect=null;
        //从数据库以及Redis中获取数据
        final List<Pair<Integer, Double>> redisCollection = userModelService.getUserLikeCategoryIds(userId);
        //不为空则赋值
        if(!ObjectUtils.isEmpty(redisCollection)){
            collect = redisCollection;
        }
        //如果依然为空 planB随机推荐
        if(ObjectUtils.isEmpty(collect)){
           return randomRecommend();
        }
        //权重推荐
        return weightRandom(collect);
    }

    private List<Integer> weightRandom(List<Pair<Integer,Double>> weights){
        List<Integer> cumulativeWeights=new ArrayList<>();
        List<Integer> resultList=new ArrayList<>();
        int total=0;
        for (Pair<Integer, Double> weight : weights) {
            total+=weight.getRight()*100;
            cumulativeWeights.add(total);
        }
        for (int i=0;i<config.getCategoryTypeNums();i++) {
            final int randomNum = random.nextInt(total);
            int idx = Collections.binarySearch(cumulativeWeights, randomNum);
            if(idx<0){
                idx=0;
            }
            resultList.add(weights.get(idx).getLeft());
        }
        return resultList;
    }
}
